package com.newx.test.open.xyz;

import lombok.Data;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.CRC32;

/**
 * @Classname Frame
 * @Description TODO 定义协议帧结构
 * @Date 2025/1/9 8:18
 * @Created by yxl
 */
public class Frame {
    private static final byte FRAME_HEADER = 0x01; // 帧头
    private static final byte FRAME_TAIL = 0x02;   // 帧尾

    private byte version;        // 版本号
    private byte commandType;    // 命令类型
    private int sequenceNumber;  // 序列号
    private int dataLength;      // 数据长度
    private byte[] checksum;     // 校验和 (4字节)
    private byte[] data;         // 数据

    public Frame() {}

    public Frame(byte version, byte commandType, int sequenceNumber, byte[] data) {
        this.version = version;
        this.commandType = commandType;
        this.sequenceNumber = sequenceNumber;
        this.data = data;
        this.dataLength = data.length;
        this.checksum = calculateChecksum(data);
    }

    public byte getVersion() {
        return version;
    }

    public byte getCommandType() {
        return commandType;
    }

    public int getSequenceNumber() {
        return sequenceNumber;
    }

    public int getDataLength() {
        return dataLength;
    }

    public byte[] getChecksum() {
        return checksum;
    }

    public byte[] getData() {
        return data;
    }

    public static Frame parseFromInputStream(DataInputStream inStream) throws IOException {
        Frame frame = new Frame();

        // 读取帧头
        byte header = inStream.readByte();
        if (header != FRAME_HEADER) {
            throw new IOException("无效的帧头");
        }

        // 读取版本号
        frame.version = inStream.readByte();

        // 读取命令类型
        frame.commandType = inStream.readByte();

        // 读取序列号
        frame.sequenceNumber = inStream.readInt();

        // 读取数据长度
        frame.dataLength = inStream.readInt();

        // 读取校验和
        frame.checksum = new byte[4];
        inStream.readFully(frame.checksum);

        // 读取数据
        frame.data = new byte[frame.dataLength];
        inStream.readFully(frame.data);

        // 读取帧尾
        byte tail = inStream.readByte();
        if (tail != FRAME_TAIL) {
            throw new IOException("无效的帧尾");
        }

        // 验证校验和
        if (!Arrays.equals(frame.checksum, calculateChecksum(frame.data))) {
            throw new IOException("校验和错误");
        }

        return frame;
    }

    public void writeToOutputStream(DataOutputStream outStream) throws IOException {
        outStream.writeByte(FRAME_HEADER); // 帧头
        outStream.writeByte(version);      // 版本号
        outStream.writeByte(commandType);  // 命令类型
        outStream.writeInt(sequenceNumber); // 序列号
        outStream.writeInt(dataLength);     // 数据长度
        outStream.write(checksum);          // 校验和
        outStream.write(data);              // 数据
        outStream.writeByte(FRAME_TAIL);    // 帧尾
        outStream.flush();
    }

    private static byte[] calculateChecksum(byte[] data) {
        CRC32 crc32 = new CRC32();
        crc32.update(data);
        return ByteBuffer.allocate(4).putInt((int) crc32.getValue()).array();
    }
}

